← Writeups

Excessive trust in client-side controls

Flaw de lógica de negocio: el precio se envía como parámetro del cliente. Añadir al carrito con price=1 compra el l33t leather jacket por 1 dólar.

Target Overview & Vulnerability Summary

El lab logic-flaws/lab-logic-flaws-excessive-trust-in-client-side-controls no valida adecuadamente el input del usuario en el flujo de compra. El precio del producto viaja como un parámetro controlable en la request de añadir al carrito: enviando price=1 se inserta el "Lightweight l33t leather jacket" por 1 dólar.

Campo Valor
Severidad Alta (abuso financiero: compra por precio manipulado)
Endpoint vulnerable POST /cart
Root cause Confianza excesiva en controles client-side: el precio se acepta desde la request en lugar de resolverse server-side

Credenciales del laboratorio: wiener:peter.

Technical Breakdown & Exploitation Flow

1. Interceptación de la request

La UI muestra el precio del producto y un formulario de añadir al carrito. Al interceptar la request de añadir, se observa que el precio se envía como campo del formulario:

POST /cart HTTP/2
Host: <LAB-ID>.web-security-academy.net
Cookie: session=<SESSION_ID>
Content-Type: application/x-www-form-urlencoded

productId=1&redir=PRODUCT&quantity=1&price=1

2. Manipulación del precio

  • productId=1 — el "Lightweight l33t leather jacket".
  • quantity=1 — una unidad.
  • price=1 — el precio enviado por el cliente. El servidor no lo ignora ni lo recalculó: lo acepta tal cual como importe de la línea.

El carrito registra la chaqueta a 1 $, se completa el checkout al precio manipulado y el lab se resuelve.

Root Cause Analysis

El servidor confía en que el precio del producto, oculto en el formulario client-side, es fiable. El precio debe ser una propiedad derivada del productId en el backend (catalogo), nunca un campo de la request. Al aceptar price del cliente, la aplicación delega una decisión económica (el importe) en el atacante: es un flaw clásico de excessive trust in client-side controls (OWASP A04/A01:2021 - Broken Access Control / insecure design).

Secure Remediation

  • Ignorar cualquier campo de precio/descuento de la request y resolver el importe desde el catálogo en el servidor:
# Servidor
def add_to_cart(request):
    product = catalog.get(product_id=request.form["productId"])   # precio del catálogo
    cart.add_line(product_id=product.id,
                  price=product.price,       # nunca desde el cliente
                  quantity=request.form.get("quantity", 1))
  • Eliminar del formulario HTML todo campo oculto que transporte valores económicos (price, discount, total), o tratarlos como no confiables.
  • Recalcular el total del carrito server-side en el checkout y validar contra el catálogo; registrar y alertar discrepancias de precio.